package org.apache.rocketmq.console.controller;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.console.script.model.EnvironDic;
import org.apache.rocketmq.console.script.model.ScriptInfo;
import org.apache.rocketmq.console.script.model.SysInfo;
import org.apache.rocketmq.console.script.service.EnvService;
import org.apache.rocketmq.console.script.service.ScriptService;
import org.apache.rocketmq.console.shiro.entity.UserInfo;
import org.apache.rocketmq.console.support.JsonResult;
import org.apache.rocketmq.console.util.JsonUtil;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/script")
public class ScriptController {
	private Logger logger = LoggerFactory.getLogger(ScriptController.class);
	@Autowired
	public ScriptService scriptService;

	@Value("${rocketmq.config.namesrvAddr}")
	private String namesrvAddr;

	// private Logger logger = LoggerFactory.getLogger(EnvController.class);
	@Autowired
	public EnvService envService;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@RequestMapping(value = "/findClusterByRegionCodeAndEnvCode.query", method = RequestMethod.POST)
	@ResponseBody
	public Object findClusterByRegionCodeAndEnvCode(@RequestBody String regionCodeAndEnvCodeJson) {
		Map<String, Object> map = new HashMap<String, Object>();

		Map regionCodeAndEnvCode = JsonUtil.obj2Map(regionCodeAndEnvCodeJson);
		String regionCode = (String) regionCodeAndEnvCode.get("regionCode");
		String enviroCode = (String) regionCodeAndEnvCode.get("envCode");

		EnvironDic environDic = scriptService.findEnvironDicByRegionCodeAndEnviroCode(regionCode, enviroCode);
		List<Map<String, Object>> clusterMapList = new LinkedList<Map<String, Object>>();

		String cluster = environDic.getRmqcluster();
		List<String> clusterList = JsonUtil.string2Obj((String) cluster, List.class);
		for (String cluster1 : clusterList) {
			Map<String, Object> clusterMap = new HashMap<>();
			clusterMap.put("cluster", cluster1);
			clusterMapList.add(clusterMap);
		}
		map.put("clusterMap", clusterMapList);

		return map;
	}

	@RequestMapping(value = "/findEnvCodeByRegionCode.query", method = RequestMethod.POST)
	@ResponseBody
	public Object findEnvCodeByRegionCode(@RequestBody String regionCode) {
		Map<String, Object> map = new HashMap<String, Object>();

		List<EnvironDic> findAllEnvironDic = scriptService.findAllEnvironDicByRegionCode(regionCode);
		List<Map<String, Object>> envMapList = new LinkedList<Map<String, Object>>();
		for (EnvironDic environDic : findAllEnvironDic) {
			Map<String, Object> envMap = new HashMap<>();
			envMap.put("enviroName", environDic.getEnviroName());
			envMap.put("enviroCode", environDic.getEnviroCode());
			envMapList.add(envMap);
		}
		map.put("envMap", envMapList);

		return map;
	}

	/**
	 * @param scriptInfoMap
	 * @return
	 * @throws MQClientException
	 * @throws RemotingException
	 * @throws InterruptedException
	 */
	// @RequiresPermissions({"rmq:admin","rmq:edit"}) // 权限管理;
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/update.do", method = RequestMethod.POST)
	@ResponseBody
	public Object update(@RequestBody Map<String, Object> scriptInfoMap)
			throws MQClientException, RemotingException, InterruptedException {
		ScriptInfo scriptInfo = new ScriptInfo();
		int id = (int) scriptInfoMap.get("id");
		ScriptInfo findScriptInfoById = scriptService.findScriptInfoById(id);

		/**
		 * id
		 */
		scriptInfo.setId(id);

		/**
		 * CreateDate
		 */
		scriptInfo.setCreateDate(findScriptInfoById.getCreateDate());
		/**
		 * Cluster
		 */
		String cluster = (String) scriptInfoMap.get("rmqcluster");
		scriptInfo.setRmqcluster(cluster);

		String servCode = (String) scriptInfoMap.get("servCode");

		/**
		 * ConsumerGroup
		 */
		Set<String> consumerGroupList = new HashSet<String>();
		Set<String> consumerSys = new HashSet<String>();

		String existOfferSysCode = (String) scriptInfoMap.get("existOfferSysCode");
		// String[] existOfferSysCodes = existOfferSysCode.split(",");
		String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
		String[] existOfferSysCodes = StringUtils.tokenizeToStringArray(existOfferSysCode, CONFIG_LOCATION_DELIMITERS);
		if (existOfferSysCodes.length >= 1) {
			for (String existOfferSysCode1 : existOfferSysCodes) {
				consumerSys.add(existOfferSysCode1);
				String consumerGroup = existOfferSysCode1 + "_" + servCode + "_CGROUP";
				consumerGroupList.add(consumerGroup);
			}
		}
		Object servOfferName = scriptInfoMap.get("servOfferName");
		if (servOfferName instanceof List) {
			List<Map<String, Object>> servOfferNameList = (List<Map<String, Object>>) servOfferName;
			for (Map<String, Object> map : servOfferNameList) {
				String sysCode = (String) map.get("sysCode");
				consumerSys.add(sysCode);
				String consumerGroup = sysCode + "_" + servCode + "_CGROUP";
				consumerGroupList.add(consumerGroup);
			}
		}

		String consumerGroup = JsonUtil.obj2String(consumerGroupList);
		scriptInfo.setConsumerGroup(consumerGroup);

		/**
		 * UpdateDate
		 */
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String formatDate = dateFormat.format(new Date());
		scriptInfo.setUpdateDate(Long.valueOf(formatDate));

		/**
		 * envId
		 */
		String regionCode = (String) scriptInfoMap.get("regionCode");
		String enviroCode = (String) scriptInfoMap.get("enviroCode");
		EnvironDic env = scriptService.findEnvironDicByRegionCodeAndEnviroCode(regionCode, enviroCode);
		scriptInfo.setEnvId(env.getId());

		/**
		 * regionCode
		 */
		scriptInfo.setRegionCode(regionCode);
		/**
		 * enviroCode
		 */
		scriptInfo.setEnviroCode(enviroCode);

		/**
		 * produceGroup
		 */
		String servUserName = (String) scriptInfoMap.get("servUserName");
		String produceGroup = servUserName + "_" + servCode + "_PGROUP";
		scriptInfo.setProduceGroup(produceGroup);

		/**
		 * servCode
		 */
		scriptInfo.setServCode(servCode);

		/**
		 * servName
		 */
		String servName = (String) scriptInfoMap.get("servName");
		scriptInfo.setServName(servName);

		/**
		 * ServOfferName
		 */
		scriptInfo.setServOfferName(JsonUtil.obj2String(consumerSys));

		/**
		 * IsDistribute
		 */
		if (consumerSys.size() <= 1) {
			scriptInfo.setIsDistribute(0);
		} else {
			scriptInfo.setIsDistribute(1);
		}

		/**
		 * servUserName
		 */
		scriptInfo.setServUserName(servUserName);

		scriptInfo.setState("1");

		/**
		 * topicName
		 */
		String reqOrRes = (String) scriptInfoMap.get("reqOrRes");
		String topicName = servUserName + "_" + servCode + "_" + reqOrRes;
		scriptInfo.setTopicName(topicName);

		/**
		 * reqOrRes
		 */
		scriptInfo.setReqOrRes(reqOrRes);

		/**
		 * versionCode
		 */
		String versionCode = (String) scriptInfoMap.get("versionCode");
		scriptInfo.setVersionCode(versionCode);

		/**
		 * 保存
		 */
		return scriptService.save(scriptInfo);
	}

	// @RequiresPermissions({"rmq:admin","rmq:edit"}) // 权限管理;
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/save.do", method = RequestMethod.POST)
	@ResponseBody
	public JsonResult<Boolean> save(@RequestBody Map<String, Object> scriptInfoMap) {
		ScriptInfo scriptInfo = new ScriptInfo();
		String regionCode = (String) ((Map<String, Object>) scriptInfoMap.get("regionName")).get("regionCode");
		String enviroCode = (String) ((Map<String, Object>) scriptInfoMap.get("enviroCode")).get("enviroCode");
		/**
		 * Cluster
		 */
		String cluster = (String) ((Map<String, Object>) scriptInfoMap.get("cluster")).get("cluster");
		scriptInfo.setRmqcluster(cluster);

		String servCode = (String) scriptInfoMap.get("servCode");

		/**
		 * ConsumerGroup
		 */
		List<String> consumerGroupList = new ArrayList<>();
		List<String> consumerSys = new ArrayList<>();
		List<Map<String, Object>> servOfferNameList = (List<Map<String, Object>>) scriptInfoMap.get("servOfferName");
		for (Map<String, Object> map : servOfferNameList) {
			String sysCode = (String) map.get("sysCode");
			consumerSys.add(sysCode);
			String consumerGroup = regionCode + "_" + sysCode + "_" + servCode + "_CGROUP";
			consumerGroupList.add(consumerGroup);
		}
		String consumerGroup = JsonUtil.obj2String(consumerGroupList);
		scriptInfo.setConsumerGroup(consumerGroup);

		/**
		 * CreateDate
		 */
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String formatDate = dateFormat.format(new Date());
		scriptInfo.setCreateDate(Long.valueOf(formatDate));

		/**
		 * envId
		 */

		EnvironDic env = scriptService.findEnvironDicByRegionCodeAndEnviroCode(regionCode, enviroCode);
		scriptInfo.setEnvId(env.getId());

		/**
		 * enviroCode
		 */
		scriptInfo.setEnviroCode(enviroCode);

		/**
		 * regionCode
		 */
		scriptInfo.setRegionCode(regionCode);

		/**
		 * produceGroup
		 */
		String servUserName = (String) ((Map<String, Object>) scriptInfoMap.get("servUserName")).get("sysCode");
		String produceGroup = regionCode + "_" + servUserName + "_" + servCode + "_PGROUP";
		scriptInfo.setProduceGroup(produceGroup);

		/**
		 * servCode
		 */
		scriptInfo.setServCode(servCode);

		/**
		 * servName
		 */
		String servName = (String) scriptInfoMap.get("servName");
		scriptInfo.setServName(servName);

		/**
		 * ServOfferName
		 */
		scriptInfo.setServOfferName(JsonUtil.obj2String(consumerSys));

		/**
		 * IsDistribute
		 */
		if (consumerSys.size() <= 1) {
			scriptInfo.setIsDistribute(0);
		} else {
			scriptInfo.setIsDistribute(1);
		}

		/**
		 * servUserName
		 */
		scriptInfo.setServUserName(servUserName);

		scriptInfo.setState("1");

		/**
		 * topicName
		 */
		String reqOrRes = (String) ((Map<String, Object>) scriptInfoMap.get("reqOrRes")).get("code");
		String topicName = regionCode + "_" + servUserName + "_" + servCode + "_" + reqOrRes;
		scriptInfo.setTopicName(topicName);

		/**
		 * reqOrRes
		 */
		scriptInfo.setReqOrRes(reqOrRes);

		/**
		 * versionCode
		 */
		String versionCode = (String) scriptInfoMap.get("versionCode");
		scriptInfo.setVersionCode(versionCode);

		/**
		 * 保存
		 */
		if (scriptService.save(scriptInfo)) {
			return new JsonResult<Boolean>(0, true, "");
		} else {
			return new JsonResult<Boolean>(1, false, "重复插入");
		}
	}

	@RequestMapping(value = "/list.query", method = RequestMethod.GET)
	@ResponseBody
	public List<ScriptInfo> list() {
		return scriptService.findAllScript();
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/findScriptInfoById.query", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> findScriptInfoById(@RequestBody String idJson) {
		Map<Object, Object> idMap = JsonUtil.obj2Map(idJson);
		int id = (int) idMap.get("id");
		Map<String, Object> map = listSysAndEnv();
		ScriptInfo scriptInfo = scriptService.findScriptInfoById(id);
		String servOfferNameJson = scriptInfo.getServOfferName();
		if (servOfferNameJson != null) {
			List<String> servOfferNameList = JsonUtil.string2Obj(servOfferNameJson, List.class);
			StringBuffer sb = new StringBuffer();
			for (String servOfferName : servOfferNameList) {
				// String code = scriptService.findSysNameBySysCode(servOfferName);
				sb.append(servOfferName + ",");
			}
			scriptInfo.setExistOfferSysCode(sb.toString().substring(0, sb.length() - 1));
		} else {
			scriptInfo.setExistOfferSysCode("");
		}
		// scriptInfo.setServOfferName("");

		EnvironDic environDic = scriptService.findOneEnvironDic(scriptInfo.getEnvId());
		if (environDic != null) {
			scriptInfo.setEnviroCode(environDic.getEnviroCode());
			scriptInfo.setEnviroName(environDic.getEnviroName());
			scriptInfo.setRegionCode(environDic.getRegionCode());
			scriptInfo.setRegionName(environDic.getRegionName());
			scriptInfo.setNameserver(environDic.getNameserver());
		}
		List<String> tmp = new ArrayList<>();
		List<Map<String, Object>> envMapList = new LinkedList<Map<String, Object>>();
		List<EnvironDic> environDics = scriptService.findAllEnvironDicByRegionCode(environDic.getRegionCode());
		for (EnvironDic environDic2 : environDics) {
			Map<String, Object> envMap = new HashMap<>();
			if (!tmp.contains(environDic2.getEnviroCode())) {
				envMap.put("enviroName", environDic2.getEnviroName());
				envMap.put("enviroCode", environDic2.getEnviroCode());
				envMapList.add(envMap);
			}
			tmp.add(environDic2.getEnviroCode());
		}
		map.put("envMap", envMapList);

		EnvironDic environDic3 = scriptService.findEnvironDicByRegionCodeAndEnviroCode(environDic.getRegionCode(),
				environDic.getEnviroCode());
		List<Map<String, Object>> clusterMapList = new LinkedList<Map<String, Object>>();
		Map<String, Object> clusterMap = new HashMap<>();
		String cluster = environDic3.getRmqcluster();
		List<String> clusterList = JsonUtil.string2Obj((String) cluster, List.class);
		System.out.println("clusterList=============" + clusterList);
		for (String cluster1 : clusterList) {
			clusterMap.put("cluster", cluster1);
			clusterMapList.add(clusterMap);
		}
		map.put("clusterMap", clusterMapList);

		List<ScriptInfo> list = new LinkedList<>();
		list.add(scriptInfo);
		map.put("scriptInfoList", list);
		map.put("scriptInfo", scriptInfo);
		return map;
	}

	@RequestMapping(value = "/changestatus.do", method = RequestMethod.POST)
	@ResponseBody
	public Object changestatus(@RequestBody String idJson) {
		Map<Object, Object> idMap = JsonUtil.obj2Map(idJson);
		int id = (int) idMap.get("id");
		ScriptInfo scriptInfo = scriptService.findScriptInfoById(id);
		String state = scriptInfo.getState();
		if ("1".equals(state)) {
			scriptInfo.setState("0");
		} else if ("0".equals(state)) {
			scriptInfo.setState("1");
		}
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String formatDate = dateFormat.format(new Date());
		scriptInfo.setUpdateDate(Long.valueOf(formatDate));
		scriptService.save(scriptInfo);
		return true;
	}

	@RequestMapping(value = "/listSysAndEnv.query", method = RequestMethod.GET)
	@ResponseBody
	public Map<String, Object> listSysAndEnv() {
		List<Map<String, Object>> sysMapList = new LinkedList<Map<String, Object>>();
		List<Map<String, Object>> envMapList = new LinkedList<Map<String, Object>>();
		List<Map<String, Object>> regionMapList = new LinkedList<Map<String, Object>>();
		List<Map<String, Object>> clusterMapList = new LinkedList<Map<String, Object>>();
//		ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();  
//		String username = user.username;
		UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();

		// System.out.println("userInfo=========================" + userInfo.getName());
		EnvironDic environDic = null;
		String[] namesrvAddrList = namesrvAddr.split(";");
		for (String nameserverAddr : namesrvAddrList) {
			environDic = envService.findOneByNameserveLike(nameserverAddr);
			if (environDic != null) {
				break;
			}
		}

		List<String> tmp = new ArrayList<>();
		int permissionId = userInfo.getPermissionId();
		if (environDic == null || permissionId == 1) {

			List<EnvironDic> findAllEnvironDic = scriptService.findAllEnvironDic();
			for (EnvironDic environDic1 : findAllEnvironDic) {
				Map<String, Object> regionMap = new HashMap<>();
				if (!tmp.contains(environDic1.getRegionCode())) {
					regionMap.put("regionName", environDic1.getRegionName());
					regionMap.put("regionCode", environDic1.getRegionCode());
					regionMapList.add(regionMap);
				}
				tmp.add(environDic1.getRegionCode());

			}
			tmp = null;
		} else {
			Map<String, Object> regionMap = new HashMap<>();
			regionMap.put("regionName", environDic.getRegionName());
			regionMap.put("regionCode", environDic.getRegionCode());
			regionMapList.add(regionMap);
		}

		Map<String, Object> map = new HashMap<String, Object>();
		List<SysInfo> findAllSysInfo = scriptService.findAllSysInfo();

		for (SysInfo sysInfo : findAllSysInfo) {
			Map<String, Object> sysMap = new HashMap<>();
			sysMap.put("sysCode", sysInfo.getCode());
			sysMap.put("sysName", sysInfo.getName());
			sysMapList.add(sysMap);
		}

		Map<String, Object> envMap = new HashMap<>();
		envMap.put("enviroName", null);
		envMap.put("enviroCode", null);
		envMapList.add(envMap);

		Map<String, Object> clusterMap = new HashMap<>();
		clusterMap.put("cluster", null);
		clusterMapList.add(clusterMap);

		map.put("sysMap", sysMapList);
		map.put("envMap", envMapList);
		map.put("regionMap", regionMapList);
		map.put("clusterMap", clusterMapList);
		return map;
	}

	@RequestMapping(value = "/downLoadScript.do", method = { RequestMethod.POST })
	@ResponseBody
	public void downLoadScript(@RequestBody ScriptInfo scriptInfo, HttpServletResponse response) {
		String region = scriptInfo.getRegionCode();
		String enviroCode = scriptInfo.getEnviroCode();

		response.setContentType("application/octet-stream");
		logger.info("op=look topicCreateOrUpdateRequest={}", JsonUtil.obj2String(scriptInfo));
		Map<Object, Object> scriptInfoMap = JsonUtil.obj2Map(scriptInfo);

		try {
			InputStream stream = this.getClass().getClassLoader()
					.getResourceAsStream("scriptTemplate/topicAndGroupScript.sh");
			BufferedReader br = new BufferedReader(new InputStreamReader(stream));
			String parse = parse(scriptInfoMap, br);
			String filename = region + "_" + enviroCode + "_" + scriptInfo.getTopicName() + ".sh";
			response.setCharacterEncoding("utf-8");
			response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
//			response.setHeader("Content-Disposition", "attachment;filename=" + filename);
			response.setHeader("Content-Disposition", filename);
			// response.setHeader("Transfer-Encoding", "chunked");
			IOUtils.copy(new StringReader(parse), response.getOutputStream(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		}

		// return true;
	}

	@SuppressWarnings("unchecked")
	protected String parse(Map<Object, Object> scriptInfo, BufferedReader ra) throws Exception {

		StringBuffer sb = new StringBuffer();

		// RandomAccessFile ra = new RandomAccessFile(file, "r");

		try {
			String line = null;
			while (null != (line = ra.readLine())) {

				Matcher m = matcher(line);
				while (m.find()) {
					for (int i = 1; i <= m.groupCount(); i++) {
						String paramName = m.group(i);
						Object paramValue = scriptInfo.get(paramName);
						if ("consumerGroup".equals(paramName)) {
							List<String> consumerGroupList = JsonUtil.string2Obj((String) paramValue, List.class);
							for (String consumerGroup : consumerGroupList) {
								String newline = line.replaceAll("@\\{" + paramName + "\\}", consumerGroup.toString());
								sb.append(newline + "\n");
							}
							line = "";
							break;
						}
						if (null == paramValue) {
							continue;
						}
						line = line.replaceAll("@\\{" + paramName + "\\}", paramValue.toString());
					}
				}

				sb.append(line + "\n");
			}
		} finally {
			ra.close();
		}
		return sb.toString();
	}

	private Matcher matcher(String str) {
		Pattern pattern = Pattern.compile("@\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
		Matcher m = pattern.matcher(str);
		return m;
	}

	/**
	 * 将首字母大写
	 * 
	 * @param str
	 * @return
	 */
	@SuppressWarnings("unused")
	private String upperFirstChar(String str) {
		char[] chars = str.toCharArray();
		chars[0] -= 32;
		return String.valueOf(chars);
	}

	/*
	 * public void test() { // 归根到底就是一个文件，普通文件 String rootPath =
	 * this.getClass().getClassLoader().getResource(
	 * "scriptTemplate/topicAndGroupScript.txt") .getFile();
	 * System.out.println(rootPath); }
	 */

}
